﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Slaks.Graphs;
using DataInput;
using Slaks.Graphs.Analysis;
using System.IO;

namespace UI
{
    class CategorizationExperiment : ExperimentItem
    {
        private CategorizationBase CategorizationAlogrithm;
        private List<int> [] _Partitions;        

        protected List<int> [] Partitions
        {
            get { return _Partitions; }
            set { _Partitions = value; }
        }

        public CategorizationExperiment(List<Field> fields, CategorizationBase experiment, String algorithmName) 
            : base ( fields, TaskType.Categorization, algorithmName )
        {
            CategorizationAlogrithm = experiment;
        }

        public override void runExperiment()
        {
            base.runExperiment();
            CategorizationAlogrithm.SetDynamicValues(Fields);
            measures.SetDynamicValues(Fields);
            GraphList trainingSet;
            GraphList testSet;
            if (Partitions == null)
            {
                Partitions = PartitionGraphs(ParsedFilesList.Count);
            }
            for (int iteration = 0; iteration < Iterations; iteration++)
            {
                GenerateTrainingAndTestSets(Partitions, Graphs, out trainingSet, out testSet, iteration);                
                CategorizationAlogrithm.setTrainingList(trainingSet);
                var resultsSet = CategorizationAlogrithm.Apply(testSet, _categoriesFile.DocumentToCategoryMap);
                Dictionary<String, Object> evaluationMeasures = measures.evaluate(resultsSet, _categoriesFile);

                SaveResults(iteration, evaluationMeasures);

            }
        }

        private static void GenerateTrainingAndTestSets(List<int>[] partitions, GraphList graphs, out GraphList trainingSet, out GraphList testSet, int iteration)
        {
            trainingSet = new GraphList();
            testSet = new GraphList();
            for (int i = 0; i < partitions.Length; i++)
            {
                if (i == iteration)
                {
                    foreach (int idx in partitions[i])
                    {                        
                        testSet.Add(graphs[idx]);
                    }
                }
                else
                {
                    foreach (int idx in partitions[i])
                    {
                        trainingSet.Add(graphs[idx]);
                    }

                }
            }
        }

        private List<int>[] PartitionGraphs(int totalAmount)
        {
            Random rnd = new Random((int)DateTime.Now.Ticks);

            var result = new List<int>[Iterations];
            List<int> indices = new List<int>(totalAmount);
            for (int i = 0; i < totalAmount; i++)
            {
                indices.Add(i);
            }
            int partitionSize = (int)Math.Floor(totalAmount * 1.0 / Iterations);

            for (int i = 0; i < Iterations; i++)
            {
                result[i] = new List<int>();
                for (int j = 0; j < partitionSize; j++)
                {
                    int idx = rnd.Next(0, indices.Count);
                    result[i].Add(indices[idx]);
                    indices.RemoveAt(idx);
                }
            }
            if (indices.Count > 0)
            {
                for (int i = 0; i < Iterations && indices.Count > 0; i++)
                {
                    int idx = rnd.Next(0, indices.Count);
                    result[i].Add(indices[idx]);
                    indices.RemoveAt(idx);
                }
            }
            return result;
        }        
    }
}
